/*
 *   项目名称：rpc-demo
 *   文件名称：com.xiaolon.rpc.loadbalancer.ConsistentHashLoadBalancer
 *
 *   创建人：  ZHOU XIAO LONG
 *   创建日期：2024/12/11
 *
 */
package com.xiaolon.rpc.loadbalancer;

import com.xiaolon.rpc.model.ServiceMetaInfo;
import org.apache.curator.retry.RetryUntilElapsed;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/*
 * 类描述：ConsistentHashLoadBalancer
 * 一致性哈希负载均衡器
 */
public class ConsistentHashLoadBalancer implements LoadBalancer{

    /**
     * 一致性hash环，存放虚拟节点
     */
    private final TreeMap<Integer, ServiceMetaInfo> virtualNodes = new TreeMap<>();

    /**
     * 虚拟节点数
     */
    private static final int VIRTUAL_NODE_NUM = 100;

    @Override
    public ServiceMetaInfo select(Map<String, Object> requestParams, List<ServiceMetaInfo> serviceMetaInfoList) {
        if(serviceMetaInfoList.isEmpty()){
            return null;
        }

        // 构建虚拟节点环
        // 每次调用均衡负载器，都会重新构造Hash环，随时能够处理节点的变化
        for (ServiceMetaInfo serviceMetaInfo : serviceMetaInfoList) {
            for (int i = 0; i < VIRTUAL_NODE_NUM; i++) {
                int hash = getHash(serviceMetaInfo.getServiceAddress()+"#"+i);
                virtualNodes.put(hash, serviceMetaInfo);
            }
        }

        // 获取调用请求的hash值
        int hash = getHash(requestParams);

        // 选择最近且大于调用请求hash值的虚拟节点
        Map.Entry<Integer, ServiceMetaInfo> entry = virtualNodes.ceilingEntry(hash);
        if(entry == null){
            // 如果没有大于等于调用请求hash值的虚拟节点，则返回环首部的节点
            entry = virtualNodes.firstEntry();
        }
        return entry.getValue();
    }

    /**
     * Hash算法，可自行实现
     * @param key
     * @return
     */
    private int getHash(Object key){
        return key.hashCode();
    }
}
